<!DOCTYPE html>



  


<html class="theme-next gemini use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.2" rel="stylesheet" type="text/css" />


  <meta name="keywords" content="Vue,Vue-router," />





  <link rel="alternate" href="/atom.xml" title="OBKoro1's Blog" type="application/atom+xml" />




  <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?v=5.1.2" />






<meta name="description" content="前言说到Vue的钩子函数，可能很多人只停留在一些很简单常用的钩子(created,mounted)，而且对于里面的区别，什么时候该用什么钩子，并没有仔细的去研究过，且Vue的生命周期在面试中也算是比较高频的考点，那么该如何回答这类问题，让人有眼前一亮的感觉呢…">
<meta name="keywords" content="Vue,Vue-router">
<meta property="og:type" content="article">
<meta property="og:title" content="Vue的钩子函数[路由导航守卫、keep-alive、生命周期钩子]">
<meta property="og:url" content="http://yoursite.com/2018/07/21/Vue的钩子函数-路由导航守卫、keep-alive、生命周期钩子/index.html">
<meta property="og:site_name" content="OBKoro1&#39;s Blog">
<meta property="og:description" content="前言说到Vue的钩子函数，可能很多人只停留在一些很简单常用的钩子(created,mounted)，而且对于里面的区别，什么时候该用什么钩子，并没有仔细的去研究过，且Vue的生命周期在面试中也算是比较高频的考点，那么该如何回答这类问题，让人有眼前一亮的感觉呢…">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="https://github.com/OBKoro1/articleImg_src/blob/master/weibo_img_move/005Y4rCogy1fthmrmtswmj30dw08t0v6.jpg?raw=true">
<meta property="og:image" content="https://raw.githubusercontent.com/OBKoro1/articleImg_src/master/juejin/164bbf610b61f3cd?w=1200&h=2800&f=jpeg&s=946212?raw=true">
<meta property="og:image" content="https://raw.githubusercontent.com/OBKoro1/articleImg_src/master/juejin/1631b6f52f7e7015.jpeg?raw=true">
<meta property="og:updated_time" content="2019-07-20T06:55:39.067Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Vue的钩子函数[路由导航守卫、keep-alive、生命周期钩子]">
<meta name="twitter:description" content="前言说到Vue的钩子函数，可能很多人只停留在一些很简单常用的钩子(created,mounted)，而且对于里面的区别，什么时候该用什么钩子，并没有仔细的去研究过，且Vue的生命周期在面试中也算是比较高频的考点，那么该如何回答这类问题，让人有眼前一亮的感觉呢…">
<meta name="twitter:image" content="https://github.com/OBKoro1/articleImg_src/blob/master/weibo_img_move/005Y4rCogy1fthmrmtswmj30dw08t0v6.jpg?raw=true">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Gemini',
    version: '5.1.2',
    sidebar: {"position":"left","display":"post","offset":12,"offset_float":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://yoursite.com/2018/07/21/Vue的钩子函数-路由导航守卫、keep-alive、生命周期钩子/"/>





  <title>Vue的钩子函数[路由导航守卫、keep-alive、生命周期钩子] | OBKoro1's Blog</title>
  





  <script type="text/javascript">
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?64d57d0b926bbd27431daa89d2e0a76b";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>




</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">OBKoro1's Blog</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-前端算法">
          <a href="/arithmetic/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-book"></i> <br />
            
            前端算法
          </a>
        </li>
      
        
        <li class="menu-item menu-item-博客最新更新">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            博客最新更新
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-commonweal">
          <a href="/404/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-heartbeat"></i> <br />
            
            公益404
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/07/21/Vue的钩子函数-路由导航守卫、keep-alive、生命周期钩子/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="OBKoro1">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/uploads/hand1.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="OBKoro1's Blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">Vue的钩子函数[路由导航守卫、keep-alive、生命周期钩子]</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-07-21T17:55:24+08:00">
                2018-07-21
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Vue/" itemprop="url" rel="index">
                    <span itemprop="name">Vue</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          
             <span id="/2018/07/21/Vue的钩子函数-路由导航守卫、keep-alive、生命周期钩子/" class="leancloud_visitors" data-flag-title="Vue的钩子函数[路由导航守卫、keep-alive、生命周期钩子]">
               <span class="post-meta-divider">|</span>
               <span class="post-meta-item-icon">
                 <i class="fa fa-eye"></i>
               </span>
               
                 <span class="post-meta-item-text">阅读次数&#58;</span>
               
                 <span class="leancloud-visitors-count"></span>
             </span>
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">字数统计&#58;</span>
                
                <span title="字数统计">
                  3,750 字
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                
                <span title="阅读时长">
                  14分钟
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <p><img src="https://github.com/OBKoro1/articleImg_src/blob/master/weibo_img_move/005Y4rCogy1fthmrmtswmj30dw08t0v6.jpg?raw=true" alt=""></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>说到Vue的钩子函数，可能很多人只停留在一些很简单常用的钩子(<code>created</code>,<code>mounted</code>)，而且对于里面的区别，什么时候该用什么钩子，并没有仔细的去研究过，且Vue的生命周期在面试中也算是比较高频的考点，那么该如何回答这类问题，让人有眼前一亮的感觉呢…</p>
<a id="more"></a>
<blockquote>
<p>个人博客了解一下：<a href="http://obkoro1.com/" target="_blank" rel="noopener">obkoro1.com</a></p>
</blockquote>
<hr>
<h2 id="Vue-Router导航守卫："><a href="#Vue-Router导航守卫：" class="headerlink" title="Vue-Router导航守卫："></a>Vue-Router导航守卫：</h2><p>有的时候，我们需要通过路由来进行一些操作，比如最常见的登录权限验证，当用户满足条件时，才让其进入导航，否则就取消跳转，并跳到登录页面让其登录。</p>
<p>为此我们有很多种方法可以植入路由的导航过程：<strong>全局的, 单个路由独享的, 或者组件级的</strong>,推荐优先阅读<a href="https://router.vuejs.org/zh/guide/advanced/navigation-guards.html" target="_blank" rel="noopener">路由文档</a></p>
<h3 id="全局守卫"><a href="#全局守卫" class="headerlink" title="全局守卫"></a>全局守卫</h3><p>vue-router全局有三个守卫：</p>
<ol>
<li>router.beforeEach 全局前置守卫 进入路由之前</li>
<li>router.beforeResolve 全局解析守卫(2.5.0+) 在beforeRouteEnter调用之后调用</li>
<li>router.afterEach 全局后置钩子 进入路由之后</li>
</ol>
<p><strong>使用方法</strong>：</p>
<pre><code>// main.js 入口文件
import router from &apos;./router&apos;; // 引入路由
router.beforeEach((to, from, next) =&gt; { 
  next();
});
router.beforeResolve((to, from, next) =&gt; {
  next();
});
router.afterEach((to, from) =&gt; {
  console.log(&apos;afterEach 全局后置钩子&apos;);
});
</code></pre><h4 id="to-from-next-这三个参数："><a href="#to-from-next-这三个参数：" class="headerlink" title="to,from,next 这三个参数："></a>to,from,next 这三个参数：</h4><p>to和from是<strong>将要进入和将要离开的路由对象</strong>,路由对象指的是平时通过this.$route获取到的路由对象。</p>
<p><strong>next:Function</strong> 这个参数是个函数，且<strong>必须调用，否则不能进入路由</strong>(页面空白)。</p>
<ul>
<li>next() 进入该路由。</li>
<li>next(false): 取消进入路由，url地址重置为from路由地址(也就是将要离开的路由地址)。</li>
<li><p>next 跳转新路由，当前的导航被中断，重新开始一个新的导航。</p>
<pre><code>我们可以这样跳转：next(&apos;path地址&apos;)或者next({path:&apos;&apos;})或者next({name:&apos;&apos;})
且允许设置诸如 replace: true、name: &apos;home&apos; 之类的选项
以及你用在router-link或router.push的对象选项。
</code></pre></li>
</ul>
<h3 id="路由独享守卫"><a href="#路由独享守卫" class="headerlink" title="路由独享守卫"></a>路由独享守卫</h3><p>如果你不想全局配置守卫的话，你可以为某些路由单独配置守卫：</p>
<pre><code>const router = new VueRouter({
  routes: [
    {
      path: &apos;/foo&apos;,
      component: Foo,
      beforeEnter: (to, from, next) =&gt; { 
        // 参数用法什么的都一样,调用顺序在全局前置守卫后面，所以不会被全局守卫覆盖
        // ...
      }
    }
  ]
})
</code></pre><h3 id="路由组件内的守卫："><a href="#路由组件内的守卫：" class="headerlink" title="路由组件内的守卫："></a>路由组件内的守卫：</h3><ol>
<li>beforeRouteEnter 进入路由前</li>
<li>beforeRouteUpdate (2.2) 路由复用同一个组件时</li>
<li>beforeRouteLeave 离开当前路由时</li>
</ol>
<p><strong>文档中的介绍：</strong></p>
<pre><code>beforeRouteEnter (to, from, next) {
  // 在路由独享守卫后调用 不！能！获取组件实例 `this`，组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
  // 在当前路由改变，但是该组件被复用时调用 可以访问组件实例 `this`
  // 举例来说，对于一个带有动态参数的路径 /foo/:id，在 /foo/1 和 /foo/2 之间跳转的时候，
  // 由于会渲染同样的 Foo 组件，因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
},
beforeRouteLeave (to, from, next) {
  // 导航离开该组件的对应路由时调用，可以访问组件实例 `this`
}
</code></pre><p><strong>beforeRouteEnter访问this</strong></p>
<p>因为钩子在组件实例还没被创建的时候调用，所以不能获取组件实例 <code>this</code>，可以通过传一个回调给<code>next</code>来访问组件实例<br>。</p>
<p>但是<strong>回调的执行时机在mounted后面</strong>,所以在我看来这里对this的访问意义不太大，可以放在<code>created</code>或者<code>mounted</code>里面。</p>
<pre><code>beforeRouteEnter (to, from, next) {
console.log(&apos;在路由独享守卫后调用&apos;);
  next(vm =&gt; {
    // 通过 `vm` 访问组件实例`this` 执行回调的时机在mounted后面，
  })
}
</code></pre><p><strong>beforeRouteLeave：</strong></p>
<p>导航离开该组件的对应路由时调用，我们用它来禁止用户离开，比如还未保存草稿，或者在用户离开前，将<code>setInterval</code>销毁，防止离开之后，定时器还在调用。</p>
<pre><code>beforeRouteLeave (to, from , next) {
  if (文章保存) {
    next(); // 允许离开或者可以跳到别的路由 上面讲过了
  } else {
    next(false); // 取消离开
  }
}
</code></pre><h3 id="关于钩子的一些知识："><a href="#关于钩子的一些知识：" class="headerlink" title="关于钩子的一些知识："></a>关于钩子的一些知识：</h3><h4 id="路由钩子函数的错误捕获"><a href="#路由钩子函数的错误捕获" class="headerlink" title="路由钩子函数的错误捕获"></a>路由钩子函数的错误捕获</h4><p>如果我们在全局守卫/路由独享守卫/组件路由守卫的钩子函数中有错误，可以这样捕获：</p>
<pre><code>router.onError(callback =&gt; { 
// 2.4.0新增 并不常用，了解一下就可以了 
  console.log(callback, &apos;callback&apos;);
});
</code></pre><p>在路由文档中还有更多的<a href="https://router.vuejs.org/zh/api/#router-%E5%AE%9E%E4%BE%8B%E6%96%B9%E6%B3%95" target="_blank" rel="noopener">实例方法</a>：动态添加路由等，有兴趣可以了解一下。</p>
<h4 id="跳转死循环，页面永远空白"><a href="#跳转死循环，页面永远空白" class="headerlink" title="跳转死循环，页面永远空白"></a>跳转死循环，页面永远空白</h4><p>我了解到的，很多人会碰到这个问题，来看一下这段伪代码：</p>
<pre><code>router.beforeEach((to, from, next) =&gt; {
  if(登录){
     next()
  }else{
      next({ name: &apos;login&apos; }); 
  }
});
</code></pre><p>看逻辑貌似是对的，但是当我们跳转到<code>login</code>之后，因为此时还是未登录状态，所以会一直跳转到<code>login</code>然后死循环，页面一直是空白的，所以：我们需要把判断条件稍微改一下。</p>
<pre><code>if(登录 || to.name === &apos;login&apos;){ next() } // 登录，或者将要前往login页面的时候，就允许进入路由
</code></pre><h4 id="全局后置钩子的跳转："><a href="#全局后置钩子的跳转：" class="headerlink" title="全局后置钩子的跳转："></a>全局后置钩子的跳转：</h4><p>文档中提到因为router.afterEach不接受<code>next</code>函数所以也不会改变导航本身，意思就是只能当成一个钩子来使用，但是我自己在试的时候发现，我们可以通过这种形式来实现跳转：</p>
<pre><code>// main.js 入口文件
import router from &apos;./router&apos;; // 引入路由
router.afterEach((to, from) =&gt; {
  if (未登录 &amp;&amp; to.name !== &apos;login&apos;) {
    router.push({ name: &apos;login&apos; }); // 跳转login
  }
});
</code></pre><p>额，通过router.beforeEach 也完全可以实现且更好，我就骚一下。</p>
<h3 id="完整的路由导航解析流程-不包括其他生命周期-："><a href="#完整的路由导航解析流程-不包括其他生命周期-：" class="headerlink" title="完整的路由导航解析流程(不包括其他生命周期)："></a>完整的路由导航解析流程(不包括其他生命周期)：</h3><ol>
<li>触发进入其他路由。</li>
<li>调用要离开路由的组件守卫<code>beforeRouteLeave</code></li>
<li>调用局前置守卫：<code>beforeEach</code></li>
<li>在重用的组件里调用 <code>beforeRouteUpdate</code></li>
<li>调用路由独享守卫 <code>beforeEnter</code>。</li>
<li>解析异步路由组件。</li>
<li>在将要进入的路由组件中调用<code>beforeRouteEnter</code></li>
<li>调用全局解析守卫 <code>beforeResolve</code></li>
<li>导航被确认。</li>
<li>调用全局后置钩子的 <code>afterEach</code> 钩子。</li>
<li>触发DOM更新(<code>mounted</code>)。</li>
<li>执行<code>beforeRouteEnter</code> 守卫中传给 next 的回调函数</li>
</ol>
<hr>
<h2 id="你不知道的keep-alive-我猜你不知道"><a href="#你不知道的keep-alive-我猜你不知道" class="headerlink" title="你不知道的keep-alive[我猜你不知道]"></a>你不知道的keep-alive[我猜你不知道]</h2><p>在开发Vue项目的时候，大部分组件是没必要多次渲染的，所以Vue提供了一个内置组件<code>keep-alive</code>来<strong>缓存组件内部状态，避免重新渲染</strong>，<a href="https://cn.vuejs.org/v2/api/#keep-alive" target="_blank" rel="noopener">文档在这里</a>。</p>
<blockquote>
<p>文档：和 <code>&lt;transition&gt;</code>相似，<code>&lt;keep-alive&gt;</code> 是一个抽象组件：它自身不会渲染一个 DOM 元素，也不会出现在父组件链中。</p>
</blockquote>
<h3 id="用法："><a href="#用法：" class="headerlink" title="用法："></a>用法：</h3><p><strong>缓存动态组件：</strong></p>
<p><code>&lt;keep-alive&gt;</code>包裹动态组件时，会缓存不活动的组件实例，而不是销毁它们，此种方式并无太大的实用意义。</p>
<pre><code>&lt;!-- 基本 --&gt;
&lt;keep-alive&gt;
  &lt;component :is=&quot;view&quot;&gt;&lt;/component&gt;
&lt;/keep-alive&gt;

&lt;!-- 多个条件判断的子组件 --&gt;
&lt;keep-alive&gt;
  &lt;comp-a v-if=&quot;a &gt; 1&quot;&gt;&lt;/comp-a&gt;
  &lt;comp-b v-else&gt;&lt;/comp-b&gt;
&lt;/keep-alive&gt;
</code></pre><p><strong>缓存路由组件：</strong></p>
<p>使用<code>keep-alive</code>可以将所有路径匹配到的路由组件都缓存起来，包括路由组件里面的组件，<code>keep-alive</code>大多数使用场景就是这种。</p>
<pre><code>&lt;keep-alive&gt;
    &lt;router-view&gt;&lt;/router-view&gt;
&lt;/keep-alive&gt;
</code></pre><h3 id="生命周期钩子："><a href="#生命周期钩子：" class="headerlink" title="生命周期钩子："></a>生命周期钩子：</h3><p>这篇既然是Vue钩子函数的专场，那肯定要扣题呀~</p>
<p>在被<code>keep-alive</code>包含的组件/路由中，会多出两个生命周期的钩子:<code>activated</code> 与 <code>deactivated</code>。</p>
<blockquote>
<p>文档：在 2.2.0 及其更高版本中，activated 和 deactivated 将会在 <keep-alive> 树内的<strong>所有嵌套组件</strong>中触发。</keep-alive></p>
</blockquote>
<p><strong>activated在组件第一次渲染时会被调用，之后在每次缓存组件被激活时调用</strong>。</p>
<p><strong>activated调用时机：</strong></p>
<p>第一次进入缓存路由/组件，在<code>mounted</code>后面，<code>beforeRouteEnter</code>守卫传给 next 的回调函数之前调用：</p>
<pre><code>beforeMount=&gt; 如果你是从别的路由/组件进来(组件销毁destroyed/或离开缓存deactivated)=&gt;
mounted=&gt; activated 进入缓存组件 =&gt; 执行 beforeRouteEnter回调
</code></pre><p>因为组件被缓存了，<strong>再次进入缓存路由/组件时，不会触发这些钩子</strong>：</p>
<pre><code>// beforeCreate created beforeMount mounted 都不会触发。
</code></pre><p>所以之后的调用时机是：</p>
<pre><code>组件销毁destroyed/或离开缓存deactivated =&gt; activated 进入当前缓存组件 
=&gt; 执行 beforeRouteEnter回调
// 组件缓存或销毁，嵌套组件的销毁和缓存也在这里触发
</code></pre><p><strong>deactivated：组件被停用(离开路由)时调用</strong></p>
<p><strong>使用了<code>keep-alive</code>就不会调用<code>beforeDestroy</code>(组件销毁前钩子)和<code>destroyed</code>(组件销毁)，因为组件没被销毁，被缓存起来了</strong>。</p>
<p>这个钩子可以看作<code>beforeDestroy</code>的替代，如果你缓存了组件，要在组件销毁的的时候做一些事情，你可以放在这个钩子里。</p>
<p>如果你离开了路由，会依次触发：</p>
<pre><code>组件内的离开当前路由钩子beforeRouteLeave =&gt;  路由前置守卫 beforeEach =&gt;
全局后置钩子afterEach =&gt; deactivated 离开缓存组件 =&gt; activated 进入缓存组件(如果你进入的也是缓存路由)
// 如果离开的组件没有缓存的话 beforeDestroy会替换deactivated 
// 如果进入的路由也没有缓存的话  全局后置钩子afterEach=&gt;销毁 destroyed=&gt; beforeCreate等
</code></pre><p>那么，如果我只是想缓存其中几个路由/组件，那该怎么做？</p>
<h3 id="缓存你想缓存的路由："><a href="#缓存你想缓存的路由：" class="headerlink" title="缓存你想缓存的路由："></a>缓存你想缓存的路由：</h3><h4 id="Vue2-1-0之前"><a href="#Vue2-1-0之前" class="headerlink" title="Vue2.1.0之前:"></a>Vue2.1.0之前:</h4><p>想实现类似的操作，你可以：</p>
<ol>
<li>配置一下路由元信息</li>
<li>创建两个<code>keep-alive</code>标签</li>
<li><p>使用<code>v-if</code>通过路由元信息判断缓存哪些路由。</p>
<pre><code>&lt;keep-alive&gt;
    &lt;router-view v-if=&quot;$route.meta.keepAlive&quot;&gt;
        &lt;!--这里是会被缓存的路由--&gt;
    &lt;/router-view&gt;
&lt;/keep-alive&gt;
&lt;router-view v-if=&quot;!$route.meta.keepAlive&quot;&gt;
    &lt;!--因为用的是v-if 所以下面还要创建一个未缓存的路由视图出口--&gt;
&lt;/router-view&gt;
//router配置
new Router({
  routes: [
    {
      path: &apos;/&apos;,
      name: &apos;home&apos;,
      component: Home,
      meta: {
        keepAlive: true // 需要被缓存
      }
    },
    {
      path: &apos;/:id&apos;,
      name: &apos;edit&apos;,
      component: Edit,
      meta: {
        keepAlive: false // 不需要被缓存
      }
    }
  ]
});
</code></pre></li>
</ol>
<h4 id="Vue2-1-0版本之后："><a href="#Vue2-1-0版本之后：" class="headerlink" title="Vue2.1.0版本之后："></a>Vue2.1.0版本之后：</h4><p>使用路由元信息的方式，要多创建一个<code>router-view</code>标签，并且每个路由都要配置一个元信息，是可以实现我们想要的效果，但是过于繁琐了点。</p>
<p>幸运的是在Vue2.1.0之后，Vue新增了两个属性配合<code>keep-alive</code>来有条件地缓存 路由/组件。</p>
<p><strong>新增属性：</strong></p>
<ul>
<li><code>include</code>：匹配的 路由/组件 会被缓存</li>
<li><code>exclude</code>：匹配的 路由/组件 不会被缓存</li>
</ul>
<p><code>include</code>和<code>exclude</code>支持三种方式来有条件的缓存路由：采用逗号分隔的字符串形式，正则形式，数组形式。</p>
<p>正则和数组形式，必须采用<code>v-bind</code>形式来使用。</p>
<p><strong>缓存组件的使用方式</strong>：</p>
<pre><code>&lt;!-- 逗号分隔字符串 --&gt;
&lt;keep-alive include=&quot;a,b&quot;&gt;
  &lt;component :is=&quot;view&quot;&gt;&lt;/component&gt;
&lt;/keep-alive&gt;

&lt;!-- 正则表达式 (使用 `v-bind`) --&gt;
&lt;keep-alive :include=&quot;/a|b/&quot;&gt;
  &lt;component :is=&quot;view&quot;&gt;&lt;/component&gt;
&lt;/keep-alive&gt;

&lt;!-- 数组 (使用 `v-bind`) --&gt;
&lt;keep-alive :include=&quot;[&apos;a&apos;, &apos;b&apos;]&quot;&gt;
  &lt;component :is=&quot;view&quot;&gt;&lt;/component&gt;
&lt;/keep-alive&gt;
</code></pre><p><strong>但更多场景中，我们会使用<code>keep-alive</code>来缓存路由</strong>：</p>
<pre><code>&lt;keep-alive include=&apos;a&apos;&gt;
    &lt;router-view&gt;&lt;/router-view&gt;
&lt;/keep-alive&gt;
</code></pre><p><strong>匹配规则：</strong></p>
<ol>
<li><strong>首先匹配组件的name选项</strong>，如果<code>name</code>选项不可用。</li>
<li>则匹配它的<strong>局部注册名称</strong>。 (父组件 <code>components</code> 选项的键值)</li>
<li><strong>匿名组件，不可匹配</strong>。</li>
</ol>
<p>比如路由组件没有<code>name</code>选项，并且没有注册的组件名。</p>
<ol start="4">
<li>只能匹配当前被包裹的组件，<strong>不能匹配更下面嵌套的子组件</strong>。</li>
</ol>
<p>比如用在路由上，只能匹配路由组件的<code>name</code>选项，不能匹配路由组件里面的嵌套组件的<code>name</code>选项。</p>
<ol start="5">
<li>文档：<code>&lt;keep-alive&gt;</code><strong>不会在函数式组件中正常工作</strong>，因为它们没有缓存实例。</li>
<li><strong><code>exclude</code>的优先级大于<code>include</code></strong></li>
</ol>
<p>也就是说：当<code>include</code>和<code>exclude</code>同时存在时，<code>exclude</code>生效，<code>include</code>不生效。</p>
<pre><code>&lt;keep-alive include=&quot;a,b&quot; exclude=&quot;a&quot;&gt;
  &lt;!--只有a不被缓存--&gt;
  &lt;router-view&gt;&lt;/router-view&gt;
&lt;/keep-alive&gt;
</code></pre><p><strong>当组件被<code>exclude</code>匹配，该组件将不会被缓存，不会调用<code>activated</code> 和 <code>deactivated</code></strong>。</p>
<hr>
<h2 id="组件生命周期钩子："><a href="#组件生命周期钩子：" class="headerlink" title="组件生命周期钩子："></a>组件生命周期钩子：</h2><p>关于组件的生命周期，是时候放出这张图片了：</p>
<p><img src="https://raw.githubusercontent.com/OBKoro1/articleImg_src/master/juejin/164bbf610b61f3cd?w=1200&amp;h=2800&amp;f=jpeg&amp;s=946212?raw=true" alt=""></p>
<p>这张图片已经讲得很清楚了，很多人这部分也很清楚了，大部分生命周期并不会用到，这里提一下几点：</p>
<ol>
<li><p><strong>ajax请求最好放在<code>created</code>里面</strong>，因为此时已经可以访问<code>this</code>了，请求到数据就可以直接放在<code>data</code>里面。</p>
<p> 这里也碰到过几次，面试官问：ajax请求应该放在哪个生命周期。</p>
</li>
<li><p><strong>关于dom的操作要放在<code>mounted</code>里面</strong>，在<code>mounted</code>前面访问dom会是<code>undefined</code>。</p>
</li>
<li><p>每次进入/离开组件都要做一些事情，用什么钩子：</p>
</li>
</ol>
<ul>
<li><p>不缓存：</p>
<p>  进入的时候可以用<code>created</code>和<code>mounted</code>钩子，离开的时候用<code>beforeDestory</code>和<code>destroyed</code>钩子,<code>beforeDestory</code>可以访问<code>this</code>，<code>destroyed</code>不可以访问<code>this</code>。 </p>
</li>
<li><p>缓存了组件：</p>
</li>
</ul>
<pre><code>缓存了组件之后，再次进入组件不会触发`beforeCreate`、`created` 、`beforeMount`、 `mounted`，**如果你想每次进入组件都做一些事情的话，你可以放在`activated`进入缓存组件的钩子中**。

同理：离开缓存组件的时候，`beforeDestroy`和`destroyed`并不会触发，可以使用`deactivated`离开缓存组件的钩子来代替。
</code></pre><hr>
<h2 id="触发钩子的完整顺序："><a href="#触发钩子的完整顺序：" class="headerlink" title="触发钩子的完整顺序："></a>触发钩子的完整顺序：</h2><p>将路由导航、<code>keep-alive</code>、和组件生命周期钩子结合起来的，触发顺序，假设是从a组件离开，第一次进入b组件：</p>
<ol>
<li><code>beforeRouteLeave</code>:路由组件的组件离开路由前钩子，可取消路由离开。</li>
<li><code>beforeEach</code>: 路由全局前置守卫，可用于登录验证、全局路由loading等。</li>
<li><code>beforeEnter</code>: 路由独享守卫</li>
<li><code>beforeRouteEnter</code>: 路由组件的组件进入路由前钩子。</li>
<li><code>beforeResolve</code>:<a href="https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%85%A8%E5%B1%80%E8%A7%A3%E6%9E%90%E5%AE%88%E5%8D%AB" target="_blank" rel="noopener">路由全局解析守卫</a></li>
<li><code>afterEach</code>:路由全局后置钩子</li>
<li><code>beforeCreate</code>:组件生命周期，不能访问<code>this</code>。</li>
<li><code>created</code>:组件生命周期，可以访问<code>this</code>，不能访问dom。</li>
<li><code>beforeMount</code>:组件生命周期</li>
<li><code>deactivated</code>: 离开缓存组件a，或者触发a的<code>beforeDestroy</code>和<code>destroyed</code>组件销毁钩子。</li>
<li><code>mounted</code>:访问/操作dom。</li>
<li><code>activated</code>:进入缓存组件，进入a的嵌套子组件(如果有的话)。</li>
<li>执行beforeRouteEnter回调函数next。</li>
</ol>
<hr>
<h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>Vue提供了很多钩子，但很多钩子我们几乎不会用到，只有清楚这些钩子函数的触发顺序以及背后的一些限制等，这样我们才能够正确的使用这些钩子，希望看了本文的同学，能对这些钩子有更加清晰的认识，使用起来更加得心应手。</p>
<h3 id="希望看完的朋友可以点个喜欢-关注，您的支持是对我最大的鼓励。"><a href="#希望看完的朋友可以点个喜欢-关注，您的支持是对我最大的鼓励。" class="headerlink" title="希望看完的朋友可以点个喜欢/关注，您的支持是对我最大的鼓励。"></a>希望看完的朋友可以点个喜欢/关注，您的支持是对我最大的鼓励。</h3><p><strong><a href="http://obkoro1.com/" target="_blank" rel="noopener">个人blog</a></strong> and <strong><a href="https://juejin.im/user/58714f0eb123db4a2eb95372" target="_blank" rel="noopener">掘金个人主页</a></strong>，如需转载，请放上原文链接并署名。码字不易，<strong>感谢</strong>支持！</p>
<p>如果喜欢本文的话，欢迎关注我的订阅号，漫漫技术路，期待未来共同学习成长。</p>
<p><img src="https://raw.githubusercontent.com/OBKoro1/articleImg_src/master/juejin/1631b6f52f7e7015.jpeg?raw=true" alt=""></p>
<p> 以上2018.7.21</p>
<p> 参考资料：</p>
<p>Vue文档</p>
<p><a href="https://segmentfault.com/a/1190000010546663" target="_blank" rel="noopener">keep-alive的深入理解与使用(配合router-view缓存整个路由页面)</a></p>

      
    </div>
    
    
    

    

    
      <div>
        <div style="padding: 10px 0; margin: 20px auto; width: 90%; text-align: center;">
  <div>听说，打赏我的人最后都找到了真爱。</div>
  <button id="rewardButton" disable="enable" onclick="var qr = document.getElementById('QR'); if (qr.style.display === 'none') {qr.style.display='block';} else {qr.style.display='none'}">
    <span>打赏</span>
  </button>
  <div id="QR" style="display: none;">

    
      <div id="wechat" style="display: inline-block">
        <img id="wechat_qr" src="/images/pay/weixin.jpg" alt="OBKoro1 微信支付"/>
        <p>微信支付</p>
      </div>
    

    
      <div id="alipay" style="display: inline-block">
        <img id="alipay_qr" src="/images/pay/ali.jpg" alt="OBKoro1 支付宝"/>
        <p>支付宝</p>
      </div>
    

    

  </div>
</div>

      </div>
    

    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tags/Vue/" rel="tag"><i class="fa fa-tag"></i> Vue</a>
          
            <a href="/tags/Vue-router/" rel="tag"><i class="fa fa-tag"></i> Vue-router</a>
          
        </div>
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2018/07/08/JS高程中的垃圾回收机制与常见内存泄露的解决方法/" rel="next" title="JS高程中的垃圾回收机制与常见内存泄露的解决方法">
                <i class="fa fa-chevron-left"></i> JS高程中的垃圾回收机制与常见内存泄露的解决方法
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2018/08/08/前端er怎样操作剪切复制以及禁止复制-破解等/" rel="prev" title="前端er怎样操作剪切复制以及禁止复制+破解等">
                前端er怎样操作剪切复制以及禁止复制+破解等 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          
  <div class="comments" id="comments">
    
  </div>


        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap" >
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
          
            <img class="site-author-image" itemprop="image"
              src="/uploads/hand1.jpg"
              alt="OBKoro1" />
          
            <p class="site-author-name" itemprop="name">OBKoro1</p>
            <p class="site-description motion-element" itemprop="description">种一棵树最好的时间是十年前,其次是现在</p>
        </div>

        <nav class="site-state motion-element">

          
            <div class="site-state-item site-state-posts">
            
              <a href="/archives">
            
                <span class="site-state-item-count">105</span>
                <span class="site-state-item-name">日志</span>
              </a>
            </div>
          

          
            
            
            <div class="site-state-item site-state-categories">
              <a href="/categories/index.html">
                <span class="site-state-item-count">20</span>
                <span class="site-state-item-name">分类</span>
              </a>
            </div>
          

          
            
            
            <div class="site-state-item site-state-tags">
              <a href="/tags/index.html">
                <span class="site-state-item-count">74</span>
                <span class="site-state-item-name">标签</span>
              </a>
            </div>
          

        </nav>

        
          <div class="feed-link motion-element">
            <a href="/atom.xml" rel="alternate">
              <i class="fa fa-rss"></i>
              RSS
            </a>
          </div>
        

        <div class="links-of-author motion-element">
          
            
              <span class="links-of-author-item">
                <a href="https://github.com/OBKoro1" target="_blank" title="GitHub">
                  
                    <i class="fa fa-fw fa-github"></i>GitHub</a>
              </span>
            
              <span class="links-of-author-item">
                <a href="https://juejin.im/user/58714f0eb123db4a2eb95372" target="_blank" title="掘金">
                  
                    <i class="fa fa-fw fa-globe"></i>掘金</a>
              </span>
            
              <span class="links-of-author-item">
                <a href="http://obkoro1.com/web_accumulate/" target="_blank" title="前端积累">
                  
                    <i class="fa fa-fw fa-globe"></i>前端积累</a>
              </span>
            
              <span class="links-of-author-item">
                <a href="https://segmentfault.com/u/obkoro1/articles" target="_blank" title="segmentfault">
                  
                    <i class="fa fa-fw fa-globe"></i>segmentfault</a>
              </span>
            
          
        </div>

        
        

        
        

        


      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#前言"><span class="nav-number">1.</span> <span class="nav-text">前言</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue-Router导航守卫："><span class="nav-number">2.</span> <span class="nav-text">Vue-Router导航守卫：</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#全局守卫"><span class="nav-number">2.1.</span> <span class="nav-text">全局守卫</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#to-from-next-这三个参数："><span class="nav-number">2.1.1.</span> <span class="nav-text">to,from,next 这三个参数：</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#路由独享守卫"><span class="nav-number">2.2.</span> <span class="nav-text">路由独享守卫</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#路由组件内的守卫："><span class="nav-number">2.3.</span> <span class="nav-text">路由组件内的守卫：</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#关于钩子的一些知识："><span class="nav-number">2.4.</span> <span class="nav-text">关于钩子的一些知识：</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#路由钩子函数的错误捕获"><span class="nav-number">2.4.1.</span> <span class="nav-text">路由钩子函数的错误捕获</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#跳转死循环，页面永远空白"><span class="nav-number">2.4.2.</span> <span class="nav-text">跳转死循环，页面永远空白</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#全局后置钩子的跳转："><span class="nav-number">2.4.3.</span> <span class="nav-text">全局后置钩子的跳转：</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#完整的路由导航解析流程-不包括其他生命周期-："><span class="nav-number">2.5.</span> <span class="nav-text">完整的路由导航解析流程(不包括其他生命周期)：</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#你不知道的keep-alive-我猜你不知道"><span class="nav-number">3.</span> <span class="nav-text">你不知道的keep-alive[我猜你不知道]</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#用法："><span class="nav-number">3.1.</span> <span class="nav-text">用法：</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#生命周期钩子："><span class="nav-number">3.2.</span> <span class="nav-text">生命周期钩子：</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#缓存你想缓存的路由："><span class="nav-number">3.3.</span> <span class="nav-text">缓存你想缓存的路由：</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#Vue2-1-0之前"><span class="nav-number">3.3.1.</span> <span class="nav-text">Vue2.1.0之前:</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Vue2-1-0版本之后："><span class="nav-number">3.3.2.</span> <span class="nav-text">Vue2.1.0版本之后：</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#组件生命周期钩子："><span class="nav-number">4.</span> <span class="nav-text">组件生命周期钩子：</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#触发钩子的完整顺序："><span class="nav-number">5.</span> <span class="nav-text">触发钩子的完整顺序：</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#结语"><span class="nav-number">6.</span> <span class="nav-text">结语</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#希望看完的朋友可以点个喜欢-关注，您的支持是对我最大的鼓励。"><span class="nav-number">6.1.</span> <span class="nav-text">希望看完的朋友可以点个喜欢/关注，您的支持是对我最大的鼓励。</span></a></li></ol></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright" >
  
  &copy;  2017 &mdash; 
  <span itemprop="copyrightYear">2019</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">OBKoro1</span>

  
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-area-chart"></i>
    </span>
    
      <span class="post-meta-item-text">Site words total count&#58;</span>
    
    <span title="Site words total count">
      156.0k
    </span>
  
</div>




<div>
<script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<span class="site-uv"><i class="fa fa-user"></i> 访问用户： <span class="busuanzi-value" id="busuanzi_value_site_uv">21621</span> 人 </span>
<span class="site-pv"><i class="fa fa-eye"></i> 访问次数： <span class="busuanzi-value" id="busuanzi_value_site_pv">68503</span> 次</span>

</div>



        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  


  











  
  <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>

  
  <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>

  
  <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>

  
  <script type="text/javascript" src="/lib/canvas-nest/canvas-nest.min.js"></script>


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.2"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.2"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.2"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.2"></script>



  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.2"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.2"></script>


  

  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.2"></script>



  


  




	





  





  








  



  





  

  
  <script src="https://cdn1.lncld.net/static/js/av-core-mini-0.6.4.js"></script>
  <script>AV.initialize("9ANFp60h6oVyxIPGlau3NOA4-gzGzoHsz", "tMdNuKMbFtN4QsekeNVu83TV");</script>
  <script>
    function showTime(Counter) {
      var query = new AV.Query(Counter);
      var entries = [];
      var $visitors = $(".leancloud_visitors");

      $visitors.each(function () {
        entries.push( $(this).attr("id").trim() );
      });

      query.containedIn('url', entries);
      query.find()
        .done(function (results) {
          var COUNT_CONTAINER_REF = '.leancloud-visitors-count';

          if (results.length === 0) {
            $visitors.find(COUNT_CONTAINER_REF).text(0);
            return;
          }

          for (var i = 0; i < results.length; i++) {
            var item = results[i];
            var url = item.get('url');
            var time = item.get('time');
            var element = document.getElementById(url);

            $(element).find(COUNT_CONTAINER_REF).text(time);
          }
          for(var i = 0; i < entries.length; i++) {
            var url = entries[i];
            var element = document.getElementById(url);
            var countSpan = $(element).find(COUNT_CONTAINER_REF);
            if( countSpan.text() == '') {
              countSpan.text(0);
            }
          }
        })
        .fail(function (object, error) {
          console.log("Error: " + error.code + " " + error.message);
        });
    }

    function addCount(Counter) {
      var $visitors = $(".leancloud_visitors");
      var url = $visitors.attr('id').trim();
      var title = $visitors.attr('data-flag-title').trim();
      var query = new AV.Query(Counter);

      query.equalTo("url", url);
      query.find({
        success: function(results) {
          if (results.length > 0) {
            var counter = results[0];
            counter.fetchWhenSave(true);
            counter.increment("time");
            counter.save(null, {
              success: function(counter) {
                var $element = $(document.getElementById(url));
                $element.find('.leancloud-visitors-count').text(counter.get('time'));
              },
              error: function(counter, error) {
                console.log('Failed to save Visitor num, with error message: ' + error.message);
              }
            });
          } else {
            var newcounter = new Counter();
            /* Set ACL */
            var acl = new AV.ACL();
            acl.setPublicReadAccess(true);
            acl.setPublicWriteAccess(true);
            newcounter.setACL(acl);
            /* End Set ACL */
            newcounter.set("title", title);
            newcounter.set("url", url);
            newcounter.set("time", 1);
            newcounter.save(null, {
              success: function(newcounter) {
                var $element = $(document.getElementById(url));
                $element.find('.leancloud-visitors-count').text(newcounter.get('time'));
              },
              error: function(newcounter, error) {
                console.log('Failed to create');
              }
            });
          }
        },
        error: function(error) {
          console.log('Error:' + error.code + " " + error.message);
        }
      });
    }

    $(function() {
      var Counter = AV.Object.extend("Counter");
      if ($('.leancloud_visitors').length == 1) {
        addCount(Counter);
      } else if ($('.post-title-link').length > 1) {
        showTime(Counter);
      }
    });
  </script>



  

  

  

  

  

</body>
</html>

